#include <user.h>
#include <ts7200.h>
#include <clockserver.h>
#include <timer.h>
#include <vic.h>
#include <isr.h>
#include <heap.h>
#include <messages.h>

void ClockNotifier() {  
  int server_tid;
  Receive(&server_tid, NULL, 0);
  Reply(server_tid, NULL, 0);

  for ( ; ; ) {
    AwaitEvent( EVENT_TIMER, NULL, 0 );
    Send(server_tid, NULL, 0, NULL, 0);
  }
  Exit();
}

void ClockServer() {
  int ticks = 0;
  clock_req msg;
  int time;
  int sender_tid;
 
  // wait heap
  heap wait_heap;
  heap_entry next_task;
  HeapInit(&wait_heap);

  // create notifier
  int notifier_tid = Create( 9, &ClockNotifier, "ClockNotifier" );
  Send(notifier_tid, NULL, 0, NULL, 0);

  // notify parent
  int parent_tid;
  Receive(&parent_tid, NULL, 0);
  Reply(parent_tid, NULL, 0);

  // register
  RegisterAs("clock-server");
  for ( ; ; ) {
    Receive( &sender_tid, (char*)&msg, sizeof(clock_req) );
    if (sender_tid == notifier_tid) {
      // tick received; update software timer!
      ticks++;
      Reply(notifier_tid, NULL, 0);
      while (!HeapEmpty(&wait_heap)) {
        HeapTop(&wait_heap, &next_task);
        if (next_task.priority > ticks)
          break;
        HeapPop(&wait_heap);
        Reply(next_task.tid, NULL, 0);
      }
    } else {
      // system call request received; handle it!
      switch (msg.type) {
      case DELAY_REQUEST:
        next_task.tid = sender_tid;
        next_task.priority = ticks + msg.ticks;
        HeapPush(&wait_heap, next_task);
        break;
      case TIME_REQUEST:
        time = ticks;
        Reply(sender_tid, (char*)&time, sizeof(int));
        break;
      case DELAY_UNTIL_REQUEST:
        next_task.tid = sender_tid;
        next_task.priority = msg.ticks;
        HeapPush(&wait_heap, next_task);
        break;
      default:
        break;
      }
    }
  }
  Exit();
}
